#include "Render.h"
#include <sstream>
#include <boost/foreach.hpp>
#include "ResourceManager.h"

#define foreach BOOST_FOREACH

using namespace sf;

Render::Render(RenderWindow* window):
window(window),
scrollView(Vector2f(160,100), Vector2f(160,100)),
pixelViewFactor((scrollView.GetHalfSize().x * 2) / window->GetWidth()),
physicsViewFactor(10.0f),
debugView(window, physicsViewFactor, pixelViewFactor),
player(0),
arial(*(ResourceManager::getInstance()->loadFont("../media/arial.ttf"))),
fps("", arial, 16 * pixelViewFactor),
benchIterations(0),
avgElapsedTime(0)
{
	window->SetView(scrollView);

	fps.SetColor(Color::Black);

	debugView.SetFlags(DebugView::e_shapeBit | DebugView::e_aabbBit);
}

Render::~Render() {}

DebugView* Render::getDebugView()
{
	return &debugView;
}

void Render::addSprite(const Sprite& sprite)
{
	Sprite copy = sprite;
	copy.SetPosition(sprite.GetPosition() * pixelViewFactor);
	copy.Scale(pixelViewFactor, pixelViewFactor);
	sprites.push_back(copy);
}

void Render::setPlayer(Player* player)
{
	this->player = player;
}

void Render::clear()
{
	//Clear before drawing
	window->Clear(Color::White);
}

void Render::update(float timeStep)
{
	foreach(const Sprite& s, sprites) {
		Vector2f pos = s.GetPosition();
		Vector2f size = s.GetSize();
		//Draw only visible sprites
		FloatRect viewRect = scrollView.GetRect();
		if (pos.x + size.x > viewRect.Left && pos.x < viewRect.Right &&
			pos.y + size.y > viewRect.Top && pos.y < viewRect.Bottom) {
			window->Draw(s);
		}
	}

	foreach(AnimatedSprite& a, animatedSprites) {
		a.update(timeStep);
		window->Draw(a);
	}

	if (player) {
		Vector2f pos = convertToScreen(player->getPosition());
		AnimatedSprite* sprite = player->getSprite();
		sprite->SetPosition(pos);
		sprite->update(timeStep);
		window->Draw(*sprite);
		scrollView.SetCenter(pos);
	}

	++benchIterations;
	avgElapsedTime += timeStep;
	if (benchIterations >= 1.0f / timeStep) {
		std::stringstream ss;
		ss << "FPS: " << 1.0f / (avgElapsedTime / benchIterations);
		fps.SetText(ss.str());
		benchIterations = 0;
		avgElapsedTime = 0;
	}
	fps.SetPosition(window->ConvertCoords(0,0));
	window->Draw(fps);

	window->Display();
}

sf::Vector2f Render::convertToScreen(const b2Vec2& physicsVector) const
{
	return sf::Vector2f(physicsVector.x * physicsViewFactor, physicsVector.y * -physicsViewFactor);
}
